package com.yeyks.rocketmq.listener;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.Action;
import com.aliyun.openservices.ons.api.ConsumeContext;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.MessageListener;
import com.google.common.collect.Lists;
import com.yeyks.account.dal.dao.AccountSetoutMapper;
import com.yeyks.common.appcommon.dto.order.AppGrabOrderDTO;
import com.yeyks.common.appcommon.result.CommonResult;
import com.yeyks.common.utils.ObjectConvertUtil;
import com.yeyks.common.utils.apputil.mqenum.TemplateType;
import com.yeyks.common.utils.apputil.redis.RedisService;
import com.yeyks.common.utils.apputil.rediskey.RedisKey;
import com.yeyks.common.utils.apputil.type.GeTuiType;
import com.yeyks.commonReference.append.rocketmq.pojo.RocketMQWebsocketBasePojo;
import com.yeyks.dao.AppAccountInfoMapper;
import com.yeyks.entity.AppAccountInfo;
import com.yeyks.service.impl.AppGeTuiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.yeyks.common.utils.apputil.rediskey.RedisKey.MQ_ONE_CUSTOMER;


/**
 * 抢单推送
 *
 * @author Administrator
 * @date 2019/08/09 16:06
 */
@Slf4j
@Component
public class MessageGrabOrderListener implements MessageListener {

    @Autowired
    private AppGeTuiService geTuiService;
    @Autowired
    private AccountSetoutMapper accountSetoutMapper;
    @Autowired
    private AppAccountInfoMapper accountInfoMapper;
    @Autowired
    private RedisService redisService;

    @Override
    public Action consume(Message message, ConsumeContext consumeContext) {
        try {
            Long startTime = System.currentTimeMillis();
            byte[] body = message.getBody();
            //获取到接收的消息，由于接收到的是byte数组，所以需要转换成字符串
            String msg = new String(body);
            //处理业务逻辑
            disposeLogic(msg);
            log.info("抢单GrabOrder检测：监听到的消息：message = {}", msg);
            Long endTime = System.currentTimeMillis();
            log.info("抢单GrabOrder检测：单次消费耗时：" + (endTime - startTime) / 1000);
        } catch (Exception e) {
            log.error("MessageListener.consume error:" + e.getMessage(), e);
        }
        return Action.CommitMessage;
    }

    /**
     * 3.4手动自动抢单，处理业务逻辑
     *
     * @param msg 监听到的信息
     */
    private void disposeLogic(String msg) {
        try {
            RocketMQWebsocketBasePojo webSocket = JSONUtil.toBean(msg, RocketMQWebsocketBasePojo.class);
            if (null != webSocket) {
                geTuiGrabPush(webSocket);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("抢单GrabOrder检测：处理监听消息异常：msg = {}", msg);
        }
    }

    /**
     * 个推(抢单消息推送)
     *
     * @param webSocket 对象信息
     */
    private void geTuiGrabPush(RocketMQWebsocketBasePojo webSocket) {
        //只进行一次推送，避免重复操作(酒店ID和时间戳组成唯一键)
        int count = 0;
        AppGrabOrderDTO appGrabOrderDTO = JSONUtil.toBean(webSocket.getBody(), AppGrabOrderDTO.class);
        String oneKey = MQ_ONE_CUSTOMER + appGrabOrderDTO.getHotelId() + ":" +
                appGrabOrderDTO.getUserId() + ":" + appGrabOrderDTO.getTimestamp();
        appGrabOrderDTO.setStartTime(new Date());
        appGrabOrderDTO.setKeepTime(RedisKey.KEEP_TIME);
        //默认设置未抢单
        appGrabOrderDTO.setStatus(0);
        //标题信息
        String title = "抢单通知，有用户发布订单了，请速速抢单！";
        //信息[用于IOS，Android获取信息]
        String json = JSONObject.toJSON(new TemplateType<String>(CommonResult.GRAB_SUCCESS,
                title,
                JSONObject.toJSONString(appGrabOrderDTO)
        )).toString();
        if (appGrabOrderDTO.getOperatorId() != null) {
            String value = redisService.get(oneKey);
            if (value != null && !"".equals(value)) {
                if (Integer.valueOf(value) == count) {
                    log.info("====================你正在重复消费消息================");
                } else {
                    geTuiService.morePush(GeTuiType.GRAB_ORDER, getCIds(appGrabOrderDTO.getOperatorId()), title, json);
                }
            } else {
                redisService.setAndExpire(oneKey, String.valueOf(count), RedisKey.KEEP_TIME, TimeUnit.MINUTES);
                //推送（个推）
                geTuiService.morePush(GeTuiType.GRAB_ORDER, getCIds(appGrabOrderDTO.getOperatorId()), title, json);
            }
            //存入缓存redis
            Map<String, Object> grabMap = ObjectConvertUtil.objectToMap(appGrabOrderDTO);
            log.info("================存入redis缓存数据{}", JSON.toJSONString(grabMap));
            redisService.saveHashString(grabMap,
                    (RedisKey.KEY + appGrabOrderDTO.getOperatorId()),
                    (RedisKey.HASH_KEY + (appGrabOrderDTO.getUserId() + ":" + appGrabOrderDTO.getTimestamp())),
                    RedisKey.KEEP_TIME,
                    TimeUnit.MINUTES);
        }
    }

    /**
     * 得到推送的 设备Id集合
     *
     * @param operatorId 当前酒店的管理员Id
     * @return 返回设备Id集合
     */
    private List<String> getCIds(Integer operatorId) {

        //子账号的相关处理， 跟ManagerId相关
        List<String> targets = this.getAccountIds(operatorId);
        List<String> cIds = Lists.newArrayList();
        //根据账户Id查询设备Id集合
        if (!CollectionUtils.isEmpty(targets)) {
            cIds = accountSetoutMapper.selectByAccountIds(targets);
        }
        return cIds;
    }

    /**
     * 根据管理员ID得到子账号及自己的集合
     *
     * @param operatorId 当前酒店的管理员Id
     * @return 返回管理员集合
     */
    private List<String> getAccountIds(Integer operatorId) {
        List<String> targets = Lists.newArrayList();
        AppAccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(operatorId);
        if (accountInfo.getManagerId() != null) {

            targets.add(accountInfo.getManagerId().toString());
        }
        //加上本身信息
        targets.add(operatorId.toString());

        return targets;
    }
}
